﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "IElement.h"
#include "IDrawingPolyCurve.h"
#include "IPolyCurve.h"
#include "ICurve2d.h"
#include "ElementId.h"
#include "IElementShapeHandle.h"
#include "IGenericElement.h"
#include "IElementBasicInformation.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IMenuItemContainerDefinition.h"
#include "ICommandMenuItemDefinition.h"

#include "GDDrawing/IDetailCurve.h"
#include "GDDrawing/DrawingCommandIds.h"
#include <bitset>

#include "UiAdapter.h"

using namespace gcmp;
namespace Sample
{
    //获取多段线当前夹点位置线段的几何对象类型
    int GetPickPolyCurveSegmentType(gcmp::IDocument* pDocument, gcmp::ElementId elementId, int positionIndex)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDocument, L"pDocument为空",L"GDMPLab",L"2024-03-30");
        IElement* pElement = pDocument->GetElement(elementId);
        if (!pElement)
            return -1;

        const IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement);
        if (!pShapeHandle)
            return -1;

        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pDocument->GetElement(pShapeHandle->GetMasterId()));
        if (!pGenericElement)
            return -1;

        IDrawingPolyCurve* pDrawingPolyCurve = quick_cast<IDrawingPolyCurve>(pGenericElement->GetExternalObject());
        if (!pDrawingPolyCurve)
            return -1;

        int curveIndex = -1;
        Int32 curveId = positionIndex & 0x1FFFFFFF;
        std::vector<Int32> curveIds = pDrawingPolyCurve->GetAllStableCurveIds();
        auto iter = std::find(curveIds.begin(), curveIds.end(), curveId);
        if (iter != curveIds.end())
        {
            curveIndex = static_cast<int>(std::distance(curveIds.begin(), iter));
        }

        const IPolyCurve* pPolyCurve = pDrawingPolyCurve->GetGeometryCurve();
        if (!pPolyCurve)
            return -1;

        OwnerPtr<ICurve2d> opCurrentCurve = pPolyCurve->GetCurve(curveIndex);
        if (!opCurrentCurve)
            return -1;

        return static_cast<int>(opCurrentCurve->GetType());
    }

    bool IsPickPolyCurveVertex(IDocument* pDoc, ElementId elementId, int& positionIndex)
    {
        positionIndex = -1;
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
        IElement* pElement = pDoc->GetElement(elementId);
        if (const IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement))
        {
            IElement* pMasterElement = pDoc->GetElement(pShapeHandle->GetMasterId());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pMasterElement, L"pMasterElement为空",L"GDMPLab",L"2024-03-30");
            IElementBasicInformation* pBasicInfo = pMasterElement->GetBasicInformation();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBasicInfo, L"pBasicInfo为空",L"GDMPLab",L"2024-03-30");
            if (pBasicInfo->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_POLYCURVE)
            {
                positionIndex = pShapeHandle->GetPositionIndexInMasterElement();
                return true;
            }
        }
        return false;
    }
    // 多段线夹点右键菜单策略
    class PolyCurveModifyStrategy :public IElementContextMenuStrategy
    {
    public:
        bool AppendContextMenu(gcmp::IElement* pElement, gcmp::IMenuItemContainerDefinition* pMenuItemContainer) const override
        {
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"断言`pElement`失败",L"GDMPLab",L"2024-03-30");
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pMenuItemContainer, L"断言`pMenuItemContainer`失败",L"GDMPLab",L"2024-03-30");

            int positionIndex = -1;
            if (!IsPickPolyCurveVertex(pElement->GetDocument(), pElement->GetElementId(), positionIndex))
                return false;
            OwnerPtr<IMenuItemDefinition> opDefMenuItemAddVertex = ICommandMenuItemDefinition::Create(gdmp::CommandId::PolyCurveAddVertex,
                gdmp::CommandId::PolyCurveAddVertex, GBMP_TR(L"添加顶点"), L"", L"");
            OwnerPtr<IMenuItemDefinition> opDefMenuItemDelVertex = ICommandMenuItemDefinition::Create(gdmp::CommandId::PolyCurveDeleteVertex,
                gdmp::CommandId::PolyCurveDeleteVertex, GBMP_TR(L"删除顶点"), L"", L"");
            OwnerPtr<IMenuItemDefinition> opDefMenuItemToStraightLine = ICommandMenuItemDefinition::Create(gdmp::CommandId::PolyCurveSegmentToStraightLine,
                gdmp::CommandId::PolyCurveSegmentToStraightLine, GBMP_TR(L"转换为直线段"), L"", L"");
            OwnerPtr<IMenuItemDefinition> opDefMenuItemToArcLine = ICommandMenuItemDefinition::Create(gdmp::CommandId::PolyCurveSegmentToArcLine,
                gdmp::CommandId::PolyCurveSegmentToArcLine, GBMP_TR(L"转换为弧线段"), L"", L"");
            std::string indexString = std::bitset<sizeof(int) * 8>(positionIndex).to_string();
            std::string auxString = indexString.substr(1, 2);
            if (auxString.size() == 2)
            {
                // 0的ASCII码为48
                int auxIndex = (auxString[0] - 48) * 2 + (auxString[1] - 48);
                // 起点或者终点
                if (auxIndex == 0 || auxIndex == 2)
                {
                    pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemAddVertex));
                    pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemDelVertex));
                }
                else if (auxIndex == 1)
                {
                    pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemAddVertex));
                    //根据线段类型显示右键“转换为直线段/转换为弧线段”
                    int type = GetPickPolyCurveSegmentType(pElement->GetDocument(), pElement->GetElementId(), positionIndex);
                    if (type == static_cast<int>(GeometryType::Arc2d)
                        || type == static_cast<int>(GeometryType::Arc3d))
                    {
                        pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemToStraightLine));
                    }
                    else if (type == static_cast<int>(GeometryType::Line2d)
                        || type == static_cast<int>(GeometryType::Line3d))
                    {
                        pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemToArcLine));
                    }
                }
                else
                    DBG_WARN(L"不支持的夹点类型",L"GDMPLab",L"2024-03-30");
            }
            return true;
        }
    };

    class DetailCurveModifyStrategy :public IElementContextMenuStrategy
    {
    public:
        bool AppendContextMenu(IElement* pElement, gcmp::IMenuItemContainerDefinition* pMenuItemContainer) const override;
    };

    bool IsPickNurbsCurveVertex(IDocument* pDoc, ElementId elementId)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
        IElement* pElement = pDoc->GetElement(elementId);
        if (const IElementShapeHandle* pShapeHandle = quick_cast<IElementShapeHandle>(pElement))
        {
            IElement* pMasterElement = pDoc->GetElement(pShapeHandle->GetMasterId());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pMasterElement, L"pMasterElement为空",L"GDMPLab",L"2024-03-30");
            const gdmp::IDetailCurve* pDetailCurve = gdmp::IDetailCurve::Cast(pMasterElement);
            if (pDetailCurve)
            {
                const gcmp::ICurve2d*  pCurve2d = pDetailCurve->GetCurve2d();
                if (pCurve2d)
                {
                    if (pCurve2d->GetType() == gcmp::GeometryType::NurbsCurve2d)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    bool DetailCurveModifyStrategy::AppendContextMenu(IElement* pElement, gcmp::IMenuItemContainerDefinition* pMenuItemContainer) const
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"断言`pElement`失败",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pMenuItemContainer, L"断言`pMenuItemContainer`失败",L"GDMPLab",L"2024-03-30");
        if (!IsPickNurbsCurveVertex(pElement->GetDocument(), pElement->GetElementId()))
            return false;
        std::wstring message =  L"添加拟合点/控制点";
        OwnerPtr<IMenuItemDefinition> opDefMenuItemAddVertex = ICommandMenuItemDefinition::Create(gdmp::CommandId::NurbsCurveAddVertex,
            gdmp::CommandId::NurbsCurveAddVertex, message, L"", L"");
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opDefMenuItemAddVertex, L"pDefMenuItemAddVertex为空",L"GDMPLab",L"2024-03-30");
        message = L"删除拟合点/控制点";
        OwnerPtr<IMenuItemDefinition> opDefMenuItemDelVertex = ICommandMenuItemDefinition::Create(gdmp::CommandId::NurbsCurveDeleteVertex,
            gdmp::CommandId::NurbsCurveDeleteVertex, message, L"", L"");
        DBG_WARN_AND_RETURN_FALSE_UNLESS(opDefMenuItemDelVertex, L"pDefMenuItemDelVertex为空",L"GDMPLab",L"2024-03-30");
        pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemAddVertex));
        pMenuItemContainer->AddSubMenuItem(TransferOwnership(opDefMenuItemDelVertex));
        return true;
    }

    namespace
    {
        //仅为示例展示用，请找到合适时机进行注册、移除
        bool stub{ []()->bool {
            // 注册多段线夹点的右键菜单策略
            UiAdapter::RegisterContextMenuStrategy(NEW_AS_OWNER_PTR(PolyCurveModifyStrategy));

            UiAdapter::RegisterContextMenuStrategy(NEW_AS_OWNER_PTR(DetailCurveModifyStrategy));
            return true;
        }()};
    }
}
